#include "BEncode.h"
#include <stdlib.h>
#include <string.h>

BEncode::BEncode()
{
	m_head = nullptr;
}

BEncode::~BEncode()
{
	
}

BItem* BEncode::load(const char* data, int len)
{
    char tmp[1024] = { 0 };

	int i = 0;
    while(i < len)
    {
        if(data[i] == 'i')
        {
			int n = parserNumber(m_head, &data[i]);
			i += n;
        }
        else if(isdigit(data[i]))
        {
			int n = parserString(m_head, &data[i]);
			i += n;
        }
		else if (data[i] == 'l')
		{
			int n = parserlist(m_head, &data[i]);
			i += n;
		}
		else if (data[i] == 'd')
		{
			int n = parserdic(m_head, &data[i]);
			i += n;
		}
    }
	return m_head;
}

int BEncode::findChar(const char* data, char c)
{
    int i = 0;
    while(true)
    {
        if(data[i] == c)
        {
            return i;
        }
        i++;
    }
}

int BEncode::parserNumber(BItem*& parent, const char* data)
{
	char tmp[1024] = { 0 };
	int end = findChar(data, 'e');
	memcpy(tmp, data + 1, end - 1);
	tmp[end - 1] = '\0';
	int n;
	sscanf(tmp, "%d", &n);
	BNumber* item = new BNumber(n);
	if (parent == nullptr)
	{
		parent = item;
	}
	else
	{
		BItem* p = parent;
		while (p->getNext() != nullptr)
		{
			p = p->getNext();
		}
		p->setNext(item);
	}
	return end + 1;
}

int BEncode::parserString(BItem*& parent, const char* data)
{
	char tmp[1024] = { 0 };
	int end = findChar(data, ':');
	memcpy(tmp, data, end);
	tmp[end] = '\0';
	int len;
	sscanf(tmp, "%d", &len);
	string s(&data[end + 1], len);

	BString* item = new BString(s);
	if (parent == nullptr)
	{
		parent = item;
	}
	else
	{
		BItem* p = parent;
		while (p->getNext() != nullptr)
		{
			p = p->getNext();
		}
		p->setNext(item);
	}
	return end + 1 + len;
}

int BEncode::parserlist(BItem*& parent, const char* data)
{
	BList* item = new BList();
	int i = 1;
	while (data[i] != 'e')
	{
		if (data[i] == 'i')
		{
			int n = parserNumber(item->m_content, &data[i]);
			i += n;
		}
		else if (isdigit(data[i]))
		{
			int n = parserString(item->m_content, &data[i]);
			i += n;
		}
		else if (data[i] == 'l')
		{
			int n = parserlist(item->m_content, &data[i]);
			i += n;
		}
		else if (data[i] == 'd')
		{
			int n = parserdic(item->m_content, &data[i]);
			i += n;
		}
	}
	if (parent == nullptr)
	{
		parent = item;
	}
	else
	{
		BItem* p = parent;
		while (p->getNext() != nullptr)
		{
			p = p->getNext();
		}
		p->setNext(item);
	}
	return i + 1;
}

int BEncode::parserdic(BItem*& parent, const char* data)
{
	BDic* item = new BDic();
	bool isFindKey = false;
	int i = 1;
	Pairs* p = nullptr;
	while (data[i] != 'e')
	{
		if (!isFindKey)
		{
			p = new Pairs();
		}
		if (data[i] == 'i')
		{
			int n = parserNumber(p->m_value, &data[i]);
			i += n;
			isFindKey = false;
		}
		else if (isdigit(data[i]))
		{
			int n = 0;
			if (!isFindKey)
			{
				isFindKey = true;
				n = parserString(p->m_key, &data[i]);
			}
			else
			{
				n = parserString(p->m_value, &data[i]);
				isFindKey = false;
			}
			i += n;
		}
		else if (data[i] == 'l')
		{
			int n = parserlist(p->m_value, &data[i]);
			i += n;
			isFindKey = false;
		}
		else if (data[i] == 'd')
		{
			int n = parserdic(p->m_value, &data[i]);
			i += n;
			isFindKey = false;
		}

		if (!isFindKey)
		{
			BItem* content = item->m_content;
			if (content == nullptr)
			{
				item->m_content = p;
			}
			else
			{
				while (content->getNext() != nullptr)
				{
					content = content->getNext();
				}
				content->setNext(p);
			}
		}
	}
	if (parent == nullptr)
	{
		parent = item;
	}
	else
	{
		BItem* p = parent;
		while (p->getNext() != nullptr)
		{
			p = p->getNext();
		}
		p->setNext(item);
	}
	return i + 1;
}

void BEncode::print()
{
    BItem* p = m_head;
	while(p != nullptr)
    {
        p->print();
        p = p->getNext();
    }
	fflush(stdout);
}
